{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "018dce87-1bf3-4ba5-9876-088319ecf75d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# File: large-five-twist.ipynb\n",
    "# Code: Claude Code and Codex\n",
    "# Review: Ryoichi Ando (ryoichi.ando@zozo.com)\n",
    "# License: Apache v2.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2eb84f3d-b318-4313-9004-d661aa55d39a",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from frontend import App\n",
    "\n",
    "# make an app\n",
    "app = App.create(\"large-five-twist\")\n",
    "\n",
    "# create a large cylinder mesh with specified radius and length\n",
    "half_length = 2.0 / 0.75\n",
    "V, F = app.mesh.cylinder(r=1, min_x=-half_length, max_x=half_length, n=1181)\n",
    "\n",
    "# add to the asset and name it \"cylinder\"\n",
    "app.asset.add.tri(\"cylinder\", V, F)\n",
    "\n",
    "# create a scene\n",
    "scene = app.scene.create()\n",
    "objs = []\n",
    "\n",
    "# arrange 5 cylinders in a circular pattern with larger radius\n",
    "n, r = 5, 1.75\n",
    "for i in range(5):\n",
    "    t = 2 * i / n * np.pi\n",
    "    x, y = r * np.cos(t), r * np.sin(t)\n",
    "    objs.append(scene.add(\"cylinder\").at(0, x, y))\n",
    "\n",
    "# configure material properties and animations for each cylinder\n",
    "for obj in objs:\n",
    "\n",
    "    # set bending stiffness, contact gap, Young's modulus, Poisson's ratio and density\n",
    "    (\n",
    "        obj.param.set(\"bend\", 500.0)\n",
    "        .set(\"contact-gap\", 1.75e-3)\n",
    "        .set(\"young-mod\", 1e4)\n",
    "        .set(\"poiss-rat\", 0.25)\n",
    "        .set(\"density\", 3.5)\n",
    "    )\n",
    "\n",
    "    # define animation parameters for large twisting motion\n",
    "    angular_vel, move_delta, scale, t_end, t_wait, s_wait = (\n",
    "        180,\n",
    "        1,\n",
    "        0.25,\n",
    "        34,\n",
    "        500 / 60,\n",
    "        16,\n",
    "    )\n",
    "    x, y, z = obj.position\n",
    "\n",
    "    # pin and animate left end - spin, scale, and move\n",
    "    left_pin = obj.pin(obj.grab([-1, 0, 0]))\n",
    "    left_pin.spin(\n",
    "        axis=[1, 0, 0],\n",
    "        angular_velocity=angular_vel,\n",
    "        t_end=t_wait,\n",
    "    ).scale(\n",
    "        scale,\n",
    "        0.0,\n",
    "        s_wait,\n",
    "        center=[-x - half_length, -y, -z],\n",
    "    ).move_by([move_delta, 0, 0], 0.0, t_end)\n",
    "\n",
    "    # pin and animate right end - spin in opposite direction, scale, and move\n",
    "    right_pin = obj.pin(obj.grab([1, 0, 0]))\n",
    "    right_pin.spin(\n",
    "        axis=[-1, 0, 0],\n",
    "        angular_velocity=angular_vel,\n",
    "        t_end=t_wait,\n",
    "    ).scale(\n",
    "        scale, 0.0, s_wait, center=[-x + half_length, -y, -z]\n",
    "    ).move_by([-move_delta, 0, 0], 0.0, t_end)\n",
    "\n",
    "    # add additional spinning motion\n",
    "    angular_vel, t_end = 180, 150\n",
    "\n",
    "    left_pin.spin(\n",
    "        center=[-x, -y, -z],\n",
    "        axis=[1, 0, 0],\n",
    "        angular_velocity=angular_vel,\n",
    "        t_start=t_wait,\n",
    "        t_end=t_end,\n",
    "    )\n",
    "\n",
    "    right_pin.spin(\n",
    "        center=[-x, -y, -z],\n",
    "        axis=[-1, 0, 0],\n",
    "        angular_velocity=angular_vel,\n",
    "        t_start=t_wait,\n",
    "        t_end=t_end,\n",
    "    )\n",
    "\n",
    "# compile the scene and report stats\n",
    "scene = scene.build().report()\n",
    "\n",
    "# set preview options\n",
    "opts = {\"wireframe\": False}\n",
    "\n",
    "# preview the initial scene\n",
    "scene.preview(options=opts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "70ce60bb-552f-4d59-9116-1cdc805cbe5f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# create a new session with the compiled scene\n",
    "session = app.session.create(scene)\n",
    "\n",
    "# set session params\n",
    "(\n",
    "    session.param.set(\"auto-save\", 10)\n",
    "    .set(\"dt\", 1 / 60)\n",
    "    .set(\"frames\", 2400)\n",
    "    .set(\"gravity\", 0.0)\n",
    "    .set(\"csrmat-max-nnz\", 90000000)\n",
    "    .set(\"keep-verts\", 100)\n",
    ")\n",
    "\n",
    "# build this session\n",
    "session = session.build()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ab76b71d-6c12-486b-9ff0-f8713f96f0a7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# start the simulation (this example takes a long time)\n",
    "session.start()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "72e221cf-7458-4753-b3f2-3f9e273c7ee0",
   "metadata": {},
   "outputs": [],
   "source": [
    "# this example takes a long time...\n",
    "# in case you shutdown the server (or kernel) and still want to restart\n",
    "# from where you have (auto) saved, do this. Do not call cells above.\n",
    "\n",
    "from frontend import App  # noqa\n",
    "\n",
    "# recover the session from auto-saved state\n",
    "session = App.recover(\"large-five-twist\")\n",
    "\n",
    "# resume if not currently running\n",
    "if not App.busy():\n",
    "    session.resume()\n",
    "\n",
    "# preview the current state\n",
    "session.preview({\"wireframe\": False})\n",
    "\n",
    "# stream the logs\n",
    "session.stream()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
